﻿using System;
using System.Linq;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;

using Microsoft.VisualBasic;

namespace GONES.Tools.Common
{
    /// <summary>
    /// 文件及文件夹工具类
    /// </summary>
    public static class FSO
    {
        /// <summary>
        /// 获得当前绝对路径
        /// </summary>
        /// <param name="strPath">指定的路径</param>
        /// <returns>绝对路径</returns>
        public static string GetMapPath(string strPath)
        {
            if (HttpContext.Current != null)
            {
                return HttpContext.Current.Server.MapPath(strPath);
            }
            else //非web程序引用
            {
                return System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strPath);
            }
        }

        /// <summary>
        /// 当前虚拟路径的物理路径
        /// </summary>
        /// <param name="strFilename"></param>
        /// <returns></returns>
        public static string GetVirtualPath(string strFilename)
        {
            return HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"] + strFilename;
        }

        /// <summary>
        /// 建立路径文件夹
        /// </summary>
        /// <param name="dirname">文件夹</param>
        public static void MakeDir(string dirname)
        {
            if (dirname.IndexOf(":\\") == -1)
                return;

            if (DirExists(dirname))
                return;

            Directory.CreateDirectory(dirname);
        }

        /// <summary>
        /// 获取路径扩展名
        /// </summary>
        /// <param name="filename"></param>
        /// <returns>扩展名，如.jpg</returns>
        public static string GetFileExt(string filename)
        {
            return Path.GetExtension(filename);
        }

        /// <summary>
        /// 获取路径文件名和扩展名
        /// </summary>
        /// <param name="filename"></param>
        /// <returns>文件名+扩展名，如a.jpg</returns>
        public static string GetFileName(string filename)
        {
            return Path.GetFileName(filename);
        }

        /// <summary>
        /// 获取路径文件名
        /// </summary>
        /// <param name="filename"></param>
        /// <returns>文件名，如abc</returns>
        public static string GetFileNameWithoutExt(string filename)
        {
            return Path.GetFileNameWithoutExtension(filename);
        }

        /// <summary>
        /// 返回文件夹是否存在
        /// </summary>
        /// <param name="dirname">文件夹名</param>
        /// <returns></returns>
        public static bool DirExists(string dirname)
        {
            return Directory.Exists(dirname);
        }

        /// <summary>
        /// 返回文件是否存在
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns></returns>
        public static bool FileExists(string filename)
        {
            return File.Exists(filename);
        }

        /// <summary>
        /// 以指定的ContentType输出指定文件文件
        /// </summary>
        /// <param name="filepath">文件路径</param>
        /// <param name="filename">输出的文件名</param>
        /// <param name="filetype">将文件输出时设置的ContentType</param>
        public static void ResponseFile(string filepath, string filename, string filetype)
        {
            Stream iStream = null;

            // 缓冲区为10k
            byte[] buffer = new Byte[10000];

            // 文件长度
            int length;

            // 需要读的数据长度
            long dataToRead;

            try
            {
                // 打开文件
                iStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);


                // 需要读的数据长度
                dataToRead = iStream.Length;

                HttpContext.Current.Response.ContentType = filetype;
                HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + Tools.UrlEncode(filename.Trim()).Replace("+", " "));

                while (dataToRead > 0)
                {
                    // 检查客户端是否还处于连接状态
                    if (HttpContext.Current.Response.IsClientConnected)
                    {
                        length = iStream.Read(buffer, 0, 10000);
                        HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
                        HttpContext.Current.Response.Flush();
                        buffer = new Byte[10000];
                        dataToRead = dataToRead - length;
                    }
                    else
                    {
                        // 如果不再连接则跳出死循环
                        dataToRead = -1;
                    }
                }
            }
            catch (Exception ex)
            {
                HttpContext.Current.Response.Write("Error : " + ex.Message);
            }
            finally
            {
                if (iStream != null)
                {
                    // 关闭文件
                    iStream.Close();
                }
            }
            HttpContext.Current.Response.End();
        }

        /// <summary>
        /// 判断文件类型是否为image
        /// </summary>
        /// <param name="contentType">文件名</param>
        /// <returns>是否可以直接显示</returns>
        public static bool IsImgtype(string contentType)
        {
            return contentType.IndexOf("image") == -1 ? false : true;
        }

        /// <summary>
        /// 判断文件名是否为浏览器可以直接显示的图片文件名
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>是否可以直接显示</returns>
        public static bool IsImgname(string filename)
        {
            filename = filename.Trim();
            if (filename.EndsWith(".") || filename.IndexOf(".") == -1)
            {
                return false;
            }
            string extname = GetFileExt(filename).ToLower();
            return (extname == ".jpg" || extname == ".jpeg" || extname == ".png" || extname == ".bmp" || extname == ".gif");
        }

        /// <summary>
        /// 删除文件夹
        /// </summary>
        /// <param name="dirname">文件夹路径</param>
        public static void DeleteDir(string dirname)
        {
            //判断当前路径是否为物理路径
            if (dirname.IndexOf(":\\") == -1)
                return;

            if (DirExists(dirname))
                Directory.Delete(dirname, true);
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="filename">文件完整路径</param>
        public static void DeleteFile(string filename)
        {
            if (filename.IndexOf(":\\") == -1)
                return;

            if (FileExists(filename))
                File.Delete(filename);
        }

        /// <summary>
        /// 文件移动
        /// </summary>
        /// <param name="sourceFileName">移动文件</param>
        /// <param name="destFileName">目标文件</param>
        /// <returns>是否成功</returns>
        public static bool MoveFile(string sourceFileName, string destFileName)
        {
            if (!FileExists(sourceFileName))
                return false;

            if (destFileName == string.Empty)
                return false;

            string destFilePath = Tools.CutString(destFileName, 0, destFileName.LastIndexOf("\\"));

            if (!DirExists(destFilePath))
                return false;

            if (FileExists(destFileName)) DeleteFile(destFileName);

            File.Move(sourceFileName, destFileName);

            return true;
        }

        /// <summary>
        /// 文件复制
        /// </summary>
        /// <param name="sourceFileName">复制文件</param>
        /// <param name="destFileName">目标文件</param>
        public static bool CopyFile(string sourceFileName, string destFileName)
        {
            if (!FileExists(sourceFileName))
                return false;

            if (destFileName == string.Empty)
                return false;

            string destFilePath = Tools.CutString(destFileName, 0, destFileName.LastIndexOf("\\"));

            if (!DirExists(destFilePath))
                return false;

            File.Copy(sourceFileName, destFileName, true);

            return true;
        }

        /// <summary>
        /// 返回指定目录下的非 UTF8 字符集文件
        /// </summary>
        /// <param name="Path">路径</param>
        /// <returns>文件名的字符串数组</returns>
        public static string[] FindNoUTF8File(string Path)
        {
            //System.IO.StreamReader reader = null;
            StringBuilder filelist = new StringBuilder();
            DirectoryInfo Folder = new DirectoryInfo(Path);
            //System.IO.DirectoryInfo[] subFolders = Folder.GetDirectories(); 
            /*
            for (int i=0;i<subFolders.Length;i++) 
            { 
                FindNoUTF8File(subFolders[i].FullName); 
            }
            */
            FileInfo[] subFiles = Folder.GetFiles();
            for (int j = 0; j < subFiles.Length; j++)
            {
                if (subFiles[j].Extension.ToLower().Equals(".htm"))
                {
                    FileStream fs = new FileStream(subFiles[j].FullName, FileMode.Open, FileAccess.Read);
                    bool bUtf8 = IsUTF8(fs);
                    fs.Close();
                    if (!bUtf8)
                    {
                        filelist.Append(subFiles[j].FullName);
                        filelist.Append("\r\n");
                    }
                }
            }
            return Tools.SplitString(filelist.ToString(), "\r\n");

        }

        //0000 0000-0000 007F - 0xxxxxxx  (ascii converts to 1 octet!)
        //0000 0080-0000 07FF - 110xxxxx 10xxxxxx    ( 2 octet format)
        //0000 0800-0000 FFFF - 1110xxxx 10xxxxxx 10xxxxxx (3 octet format)

        /// <summary>
        /// 判断文件流是否为UTF8字符集
        /// </summary>
        /// <param name="sbInputStream">文件流</param>
        /// <returns>判断结果</returns>
        private static bool IsUTF8(FileStream sbInputStream)
        {
            int i;
            byte cOctets;  // octets to go in this UTF-8 encoded character 
            byte chr;
            bool bAllAscii = true;
            long iLen = sbInputStream.Length;

            cOctets = 0;
            for (i = 0; i < iLen; i++)
            {
                chr = (byte)sbInputStream.ReadByte();

                if ((chr & 0x80) != 0) bAllAscii = false;

                if (cOctets == 0)
                {
                    if (chr >= 0x80)
                    {
                        do
                        {
                            chr <<= 1;
                            cOctets++;
                        }
                        while ((chr & 0x80) != 0);

                        cOctets--;
                        if (cOctets == 0) return false;
                    }
                }
                else
                {
                    if ((chr & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    cOctets--;
                }
            }

            if (cOctets > 0)
            {
                return false;
            }

            if (bAllAscii)
            {
                return false;
            }

            return true;

        }

        /// <summary>
        /// 格式化字节数字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string FormatBytesStr(int bytes)
        {
            if (bytes > 1073741824)
            {
                return ((double)(bytes / 1073741824)).ToString("0") + "G";
            }
            if (bytes > 1048576)
            {
                return ((double)(bytes / 1048576)).ToString("0") + "M";
            }
            if (bytes > 1024)
            {
                return ((double)(bytes / 1024)).ToString("0") + "K";
            }
            return bytes.ToString() + "Bytes";
        }

        /// <summary>
        /// 保存上传的文件
        /// </summary>
        /// <param name="key">WebConfig的appSettings的key值</param>
        /// <param name="file"></param>
        /// <param name="length">字节大小</param>
        /// <param name="fileext">允许的扩展名</param>
        /// <returns>返回文件的URL路径</returns>
        public static string SavefileFromUpdate(string key, HttpPostedFile file, int length, params string[] fileexts)
        {
            if (file == null || file.ContentLength == 0)
            {
                //return "上传的文件为空！";
                throw new Exception("上传的文件为空！");
            }

            if (length > 0 && file.ContentLength > length)
            {
                //return string.Format("所上传的文件大小({0})超过指定大小({1})！", FormatBytesStr(file.ContentLength), FormatBytesStr(length));
                throw new Exception(string.Format("所上传的文件大小({0})超过指定大小({1})！",
                    FormatBytesStr(file.ContentLength), FormatBytesStr(length)));
            }

            string file_ext = GetFileExt(file.FileName);

            if (fileexts != null)
            {
                if (!Tools.InArray(file_ext, fileexts, true))
                {
                    //return "文件类型不符合要求！";
                    throw new Exception("文件类型不符合要求！");
                }
            }

            string cfg_prefix = ConfigurationManager.AppSettings[key];
            if (string.IsNullOrEmpty(cfg_prefix))
            {
                cfg_prefix = "~/upload";
            }
            cfg_prefix += "/" + DateTime.Now.ToString("yyyyMM");

            MakeDir(GetMapPath(cfg_prefix.Replace(@"/", @"\")));

            string file_url = cfg_prefix + "/" + DateTime.Now.ToString("ddHHmmss") + Tools.CutString(Rnd.Guid, 0, 4) + file_ext;

            file.SaveAs(GetMapPath(file_url.Replace(@"/", @"\")));

            return file_url;
        }

        /// <summary>
        /// 文件下载
        /// </summary>
        /// <param name="filepath">文件路径</param>
        /// <param name="filename">文件名</param>
        public static void DownFile(string filepath,string filename)
        {
            try
            {
                FileInfo file = new FileInfo(filepath);
                if (file.Exists)
                {
                    HttpContext.Current.Response.Clear();
                    HttpContext.Current.Response.ClearHeaders();
                    HttpContext.Current.Response.Buffer = false;
                    HttpContext.Current.Response.ContentType = HttpContext.Current.Response.ContentType = "application/octet-stream";
                    HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8));
                    HttpContext.Current.Response.AppendHeader("Content-Length", file.Length.ToString());
                    HttpContext.Current.Response.WriteFile(file.FullName);
                    HttpContext.Current.Response.Flush();
                    //HttpContext.Current.Response.End();
                }
                else
                {
                    
                    HttpContext.Current.Response.Write("文件不存在！");
                }
            }
            catch (Exception ex)
            {
                System.IO.File.AppendAllText(@"c:\1.txt", ex.ToString());
                HttpContext.Current.Response.Write("下载出错！" + ex.Message);
            }
        }
    }
}
